/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package poker.geneticAlgorithm;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;

/**
 *
 * @author Benjamin L. Brodie <blbrodie@gmail.com>
 */
public class GaussianMutation implements Mutation<Individual<Double>> {
    Random random;
    double standardDeviation;
    double range;
   

    /**
     * Adds a gaussian mustation with the given standard deviation to the current
     * value. Does this for all values. Mean is 0.0. If the resulting value is
     * greater or lower than the range, will be set to the range value.
     * 
     * @param individuals the list of individuals to be mutated
     * @return the mutated individuals
     */
    public List<Individual<Double>> mutate(List<Individual<Double>> individuals){
        
        List<Individual<Double>> mutatedIndividuals = 
                                 new ArrayList<Individual<Double>>();
        
        double weightUpdate;
        for (Individual<Double> individual : individuals){
            
            List<Double> weights = individual.getList(); //copy list
            
            //loop and update each value in the weight list
            for (ListIterator<Double> iter = 
                          weights.listIterator(); iter.hasNext();){
                weightUpdate = iter.next() + (random.nextGaussian() * standardDeviation);
                
                //check for range
                if (weightUpdate > range){
                    iter.set(range);
                }
                else if (weightUpdate < -range){
                    iter.set(-range);
                }
                else
                    iter.set(weightUpdate);
                
            }
            
            //add the updated list to an individual and to the list of ind
            mutatedIndividuals.add(new WeightsIndividual(weights));
            
        }        
        return mutatedIndividuals;
    }
    
    /**
     * Applies gaussian mutation with the given standard deviation and holds values
     * within their range. The mean is 0.0. The mutate method adds the gaussian value (does not
     * multiply it) by the previous value.
     * 
     * 
     * @param range The positive and negative maximums, eg, a range of 1.0 means
     *              all values must be between -1.0 and 1.0.
     * @param standardDeviation the standard deviation (ex, 1.0)
     */
    public GaussianMutation(double range, double standardDeviation){
        
        if (standardDeviation < 0){
            throw new IllegalArgumentException("standardDeviation must be positive value");
        }
        
        this.standardDeviation = standardDeviation;
        this.random = new Random();
        this.range = range;
    }   
    
}
